<?php
declare (strict_types=1);

namespace think\admin\service;

use think\admin\model\SysOrg;
use think\admin\model\SysRelation;
use think\admin\model\SysUser;
use think\admin\Service;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;

/**
 * 数据权限服务
 * Class DataScopeService
 * @package think\admin\service
 */
class DataScopeService extends Service
{

    /**
     * 数据范围查询
     * @return $this|void
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function dataRange()
    {
        if (AdminService::isSuper()) {
            return $this;
        }
        if (empty($this->setDataScope())) {
            return $this;
        }
    }

    /**
     * 获取用户ID集合
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function setDataScope(): array
    {
        return $this->getOrgUserIdsBy($this->getPermissionScope());
    }

    /**
     * 根据权限数据获取相关所有相关用户ID
     * @param array $permissionData
     * @return array
     */
    public function getOrgUserIdsBy(array $permissionData): array
    {
        if (empty($permissionData)) {
            return [0, '账号未分配角色，请先分配角色。', 0, 0];
        }

        $user = AdminService::getUser();
        $node = NodeService::fullNode();
        $permissions = searchArrByValue($permissionData, 'apiUrl', $node);

        if (empty($permissions)) {
            return [0, '账号无该数据的读取权限。', 0, 0];
        }

        $userIds = [];
        $isAll = false;

        foreach ($permissions as $role) {
            switch ($role['scopeCategory']) {
                case 'SCOPE_ALL':
                    //全部
                    $isAll = true;
                    break;
                case 'SCOPE_ORG_DEFINE':
                    //自定义
                    $userIds = $this->ScopeOrgDefineByUserIds($userIds, $role['scopeDefineOrgIdList']);
                    break;
                case 'SCOPE_ORG':
                    //本部门
                    $userIds = $this->ScopeOrgByUserIds($user['org']['id'], $user['id']);
                    break;
                case 'SCOPE_ORG_CHILD':
                    // 本部门及以下
                    $userIds = $this->ScopeOrgChildByUserIds($user['org']['id']);
                    break;
                case 'SCOPE_SELF':
                    //本人
                    $userIds = $this->ScopeSelfByUserIds($user['id']);
                    break;
                default:
                    break;
            }
            // 如果有全部数据 直接跳出
            if ($isAll) {
                break;
            }
        }

        return $userIds;
    }

    /**
     * 自定义(SCOPE_ORG_DEFINE)情况下所有用户ID
     * @param array $userIds
     * @param array $scopeDefineOrgIdList
     * @return array
     */
    protected function ScopeOrgDefineByUserIds(array $userIds, array $scopeDefineOrgIdList): array
    {
        return array_merge($userIds, $this->getUserIdsByOrgId($scopeDefineOrgIdList));
    }

    /**
     * 获取UserID
     * @param array $ids
     * @return array
     */
    protected function getUserIdsByOrgId(array $ids): array
    {
        return SysUser::mk()->whereIn('orgId', implode(',', $ids))->column('id');
    }

    /**
     * 本部本所有用户ID
     * @param int $userOrgId
     * @param int $userId
     * @return array
     */
    protected function ScopeOrgByUserIds(int $userOrgId, int $userId): array
    {
        $orgUserIds = $userOrgId ? $this->getUserIdsByOrgId([$userOrgId]) : [];
        return array_unique(array_merge([$userId], $orgUserIds));
    }

    /**
     * 本部门及下属部分所有用户ID
     * @param int $userOrgId
     * @return array
     */
    protected function ScopeOrgChildByUserIds(int $userOrgId): array
    {
        $orgIds = $userOrgId ? SysOrg::mk()->where(['parentId' => $userOrgId])->column('id') : [];
        array_unshift($orgIds, $userOrgId);
        return $this->getUserIdsByOrgId(array_unique($orgIds));
    }

    /**
     * 本人权限
     * @param int $userId
     * @return int[]
     */
    protected function ScopeSelfByUserIds(int $userId): array
    {
        return [$userId];
    }

    /**
     * 根据用户的角色或用户ID获取该用户的权限
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getPermissionScope(): array
    {
        $permissions = [];
        $roleIds = AdminService::getRoles();
        $userId = AdminService::getUserId();

        if (!empty($roleIds)) {
            $permissions = SysRelation::mk()->where(['category' => 'SYS_ROLE_HAS_PERMISSION'])
                ->whereIn('object_id', $roleIds)
                ->select()
                ->toArray();
        } else {
            $permissions = SysRelation::mk()->where(['category' => 'SYS_USER_HAS_PERMISSION'])
                ->where(['object_id' => $userId])
                ->select()
                ->toArray();
        }

        $permissionData = [];

        foreach ($permissions as $v) {
            $extJson = json_decode($v['extJson'], true);
            $apiUrl = isset($extJson['apiUrl']) ? NodeService::fullNode($extJson['apiUrl']) : $v['targetId'];
            $scopeCategory = isset($extJson['scopeCategory']) ? $extJson['scopeCategory'] : 'SCOPE_SELF';
            $scopeDefineOrgIdList = isset($extJson['scopeDefineOrgIdList']) ? $extJson['scopeDefineOrgIdList'] : [];
            $scopeDefineOrgIdText = implode(',', $scopeDefineOrgIdList);

            $permissionData[] = [
                'roleIds' => $roleIds,
                'apiUrl' => $apiUrl,
                'scopeCategory' => $scopeCategory,
                'scopeDefineOrgIdList' => $scopeDefineOrgIdList,
                'scopeDefineOrgIdText' => $scopeDefineOrgIdText
            ];
        }

        return $permissionData;
    }

}